home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
public
/
RTF
/
image.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-01
|
26KB
|
1,015 lines
#ifndef __lint
static char rcsid[] = "$Id: image.c,v 1.1 92/11/23 12:58:54 pcd Exp Locker: pcd $";
#endif
/*
* image.c
*
* convert a hex-encoded sunraster/RLE string into a Pixmap
* should handle pseudocolor/staticcolor to 16 bits
* should handle truecolor/directcolor to 32 bits
*
* Wade Smith Wed Nov 20 20:04:48 CST 1991
*
*/
/*
* $Log: image.c,v $
* Revision 1.1 92/11/23 12:58:54 pcd
* Initial checkin
*
* Revision 1.3 92/06/12 16:03:58 connolly
* *** empty log message ***
*
* Revision 1.5 92/01/03 13:59:44 wsmith
* added a check for non-null property buffer before freeing it
*
* Revision 1.4 91/12/18 13:35:36 wsmith
* fixed dependence on /usr/avs - notes avs3 # 460
* corrected some portability issues - bigendian vs. littleendian
*
* Revision 1.9 91/12/16 16:19:49 wsmith
* fixed depended on /usr/avs installation directory
*
* Revision 1.8 91/12/16 08:59:53 wsmith
* support for big-endian and little-endian clients
* removed check of XPutImage return value
*
* Revision 1.7 91/11/25 13:16:51 wsmith
* added support for 1-bit sunraster/RLE images
*
* Revision 1.6 91/11/21 12:21:09 wsmith
* ifdef'd some code used mainly for debugging - several XQueryColor() calls
*
* Revision 1.5 91/11/21 11:15:04 wsmith
* fixed several lint complaints
*
* Revision 1.4 91/11/21 09:58:15 wsmith
* added rcs id and log entries
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <sys/param.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include "rasterfile.h"
#define MAXRGB 8
#define MAXGREY 256
#define MAXCOLS (MAXRGB*MAXRGB*MAXRGB+MAXGREY)
#define DEFRGB 6
#define DEFGREY 26
#define MINRGB 4
#define MAXCOLORS 256
#define RCOL 0
#define GCOL 1
#define BCOL 2
#define MAXSIZE 8192
#define DEF_AVS_PATH "/usr/avs"
#define RC_FILE ".avsrc"
#define SYS_RC_FILE "runtime/avsrc"
static char *endian = "\377\0";
#define IS_BIG_ENDIAN (*(short*)endian<0)
#define IS_LITTLE_ENDIAN (*(short*)endian>0)
typedef struct raster {
int width, height;
int ncolors;
unsigned char map[MAXCOLORS][3];
unsigned char *image;
} Raster;
typedef struct avsinfo {
Colormap colormap;
int numred, numgreen, numblue;
int numgrey;
unsigned short rgbmap[MAXRGB][MAXRGB][MAXRGB];
unsigned short greymap[MAXGREY];
unsigned char avsmap[MAXCOLS][3];
} AvsInfo;
typedef struct rasterfile RF;
static AvsInfo *saveinfo;
static GC gc;
static float Gamma;
static int NumRed = -1,
NumGreen = -1,
NumBlue = -1,
NumGrey = -1;
static unsigned char tohex[256] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0,0,10,11,12,13,14,
15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,11,12,13,14,15,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,
};
extern char *getenv();
/* count trailing zero bits */
static int
count_zeros(unsigned long i)
{
int n = 0;
if (i)
for (; !(i&1); n++)
i >>= 1;
return n;
}
/* count one bits in bit mask */
static int
count_ones(unsigned long i)
{
int n;
for (n = 0; i; i >>= 1)
if (i&1)
n++;
return n;
}
/* shift left on positive count, right on negative */
static unsigned long
ishift(unsigned long i, int count)
{
return count >= 0 ? (i<<count) : (i>>(-count));
}
/* reverse the bytes in a *(int *) */
static void
reverse_int(int *integer)
{
char *p = (char *)integer, tmp;
int i, j;
for (i = 0, j = sizeof(int)-1; i < j; i++, j--) {
tmp = p[i];
p[i] = p[j];
p[j] = tmp;
}
}
/* generate colormap value from an index over a range */
static int
MapCorrect(int i, int max)
{
if (i <= 0) return 0;
if (i >= max-1) return 255;
return (i*255)/(max-1);
}
/* open AVS avsrc file */
static FILE *
RCopen()
{
char *avs_path;
char *class, *home;
char path[MAXPATHLEN];
FILE *stream;
class = getenv("DISPLAYCLASS");
if (class) {
(void) sprintf(path, "%s.%s", RC_FILE, class);
if ((stream = fopen(path, "r")) != NULL)
return stream;
}
if ( (stream = fopen(RC_FILE, "r")) != NULL )
return stream;
home = getenv("HOME");
if (home) {
if (class) {
(void) sprintf(path, "%s/%s.%s", home, RC_FILE, class);
if ( (stream = fopen(path, "r")) != NULL )
return stream;
}
(void) sprintf(path, "%s/%s", home, RC_FILE);
if ( (stream = fopen(path, "r")) != NULL )
return stream;
}
avs_path = getenv("AVS_PATH");
if (!avs_path) avs_path = DEF_AVS_PATH;
if (class) {
(void) sprintf(path, "%s/%s.%s", avs_path, SYS_RC_FILE, class);
if ( (stream = fopen(path, "r")) != NULL )
return stream;
}
(void) sprintf(path, "%s/%s", avs_path, SYS_RC_FILE);
return fopen(path, "r");
}
/* get value from avsrc file given property string */
static char *
RCget(const char* string)
{
static char line[BUFSIZ];
FILE *stream;
stream = RCopen();
if (stream == NULL) return NULL;
while (fgets(line, BUFSIZ, stream) != NULL) {
char *tok, *end;
int len, ch;
len = strlen(line);
if (line[len-1] != '\n') {
while ( (ch = getc(stream)) != '\n' )
if (ch == EOF) {
(void) fclose(stream);
return NULL;
}
continue;
} else
line[len-1] = '\0';
if (line[0] == '#')
continue;
tok = line;
while (*tok == ' ' || *tok == '\t') tok++;
for (end = tok; *end && *end != ' ' && *end != '\t'; end++) ;
if (*end) *end++ = '\0';
if (!strcmp(tok, string)) {
(void) fclose(stream);
return end;
}
}
(void) fclose(stream);
return NULL;
}
/* convert hex string to integer */
static int
GetHexadecimal(char* str, int* hex)
{
char *tok, *endptr;
if ((tok = strtok(str, " ")) == NULL) return -1;
*hex = (int) strtol(tok, &endptr, 16);
return *endptr ? -1 : 0;
}
/* handle truecolor and directcolor colormap needs */
static AvsInfo *
TrueAvsInfo(Display* display, int screen, Visual* visual)
{
int i;
int r,g,b;
int red_bits, green_bits, blue_bits;
int red_shift, green_shift, blue_shift;
AvsInfo *avsinfo;
avsinfo = (AvsInfo *) malloc( sizeof(AvsInfo) );
if (avsinfo == NULL) return NULL;
red_shift = count_zeros(visual->red_mask);
green_shift = count_zeros(visual->green_mask);
blue_shift = count_zeros(visual->blue_mask);
red_bits = count_ones(visual->red_mask);
green_bits = count_ones(visual->green_mask);
blue_bits = count_ones(visual->blue_mask);
if (visual->class == DirectColor) {
int map_size = count_zeros(visual->map_entries);
avsinfo->colormap = XCreateColormap(display,
DefaultRootWindow(display), visual, AllocAll);
for (i = visual->map_entries-1; i >= 0; i--) {
XColor color;
r = ishift(i, red_shift+red_bits-map_size);
g = ishift(i, green_shift+green_bits-map_size);
b = ishift(i, blue_shift+blue_bits-map_size);
color.pixel = (r & visual->red_mask) |
(g & visual->green_mask) |
(b & visual->blue_mask) ;
color.red = MapCorrect(i, 1<<red_bits)<<8;
color.green = MapCorrect(i, 1<<green_bits)<<8;
color.blue = MapCorrect(i, 1<<blue_bits)<<8;
color.flags = DoRed | DoGreen | DoBlue;
XStoreColor(display, avsinfo->colormap, &color);
}
} else
avsinfo->colormap = DefaultColormap(display, screen);
return avsinfo;
}
#ifdef DEBUG
/* lookup actual colors allocated from colormap */
static void
GetAvsColormap(Display* display, AvsInfo* avsinfo)
{
int i;
int r,g,b;
XColor color;
for (r = 0; r < avsinfo->numred; r++)
for (g = 0; g < avsinfo->numgreen; g++)
for (b = 0; b < avsinfo->numblue; b++) {
i = avsinfo->rgbmap[r][g][b];
color.pixel = i;
XQueryColor(display, avsinfo->colormap, &color);
avsinfo->avsmap[i][RCOL] = color.red>>8;
avsinfo->avsmap[i][GCOL] = color.green>>8;
avsinfo->avsmap[i][BCOL] = color.blue>>8;
}
for (g = 0; g < avsinfo->numgrey; g++) {
i = avsinfo->greymap[g];
color.pixel = i;
XQueryColor(display, avsinfo->colormap, &color);
avsinfo->avsmap[i][RCOL] = color.red>>8;
avsinfo->avsmap[i][GCOL] = color.green>>8;
avsinfo->avsmap[i][BCOL] = color.blue>>8;
}
}
#endif /*DEBUG*/
/* get colormap info from AVS as property on root window */
static AvsInfo *
GetAvsInfo(Display* display, int screen, Visual* visual)
{
char value[MAXSIZE];
unsigned char *prop;
int actual_format;
int i,r,g,b;
int ncolors;
long char_offset;
unsigned long nitems, bytes_after;
Atom property, actual_type;
AvsInfo avsinfo, *new;
Window root;
if (visual->class == TrueColor || visual->class == DirectColor)
return TrueAvsInfo(display, screen, visual);
if (visual->class != PseudoColor)
return NULL;
property = XInternAtom(display, "AVS_PSEUDO_COLORMAP", False);
root = DefaultRootWindow(display);
char_offset = 0L;
while (XGetWindowProperty(display, root, property,
char_offset/sizeof(long),
(MAXSIZE-char_offset)/sizeof(long), False,
XA_STRING, &actual_type, &actual_format,
&nitems, &bytes_after, &prop) == Success) {
if (actual_type != XA_STRING || prop == NULL ||
actual_format != 8 || char_offset+nitems >= MAXSIZE) {
if (prop) XFree( (char *)prop );
return NULL;
}
memcpy(value+char_offset, (char *)prop, nitems);
char_offset += nitems;
XFree( (char *)prop );
if (bytes_after <= 0)
break;
}
if (char_offset <= 0L)
return NULL;
value[char_offset] = '\0';
if (GetHexadecimal(value, (int *)&avsinfo.colormap) == -1) return NULL;
if (GetHexadecimal(NULL, &avsinfo.numred) == -1) return NULL;
if (GetHexadecimal(NULL, &avsinfo.numgreen) == -1) return NULL;
if (GetHexadecimal(NULL, &avsinfo.numblue) == -1) return NULL;
if (GetHexadecimal(NULL, &avsinfo.numgrey) == -1) return NULL;
if (avsinfo.numred < 0 || MAXRGB < avsinfo.numred ||
avsinfo.numgreen < 0 || MAXRGB < avsinfo.numgreen ||
avsinfo.numblue < 0 || MAXRGB < avsinfo.numblue ||
avsinfo.numgrey < 0 || MAXGREY < avsinfo.numgrey)
return NULL;
ncolors = (avsinfo.numred*avsinfo.numgreen*avsinfo.numblue)+
avsinfo.numgrey;
if (ncolors > MAXCOLS)
return NULL;
for (r = 0; r < avsinfo.numred; r++)
for (g = 0; g < avsinfo.numgreen; g++)
for (b = 0; b < avsinfo.numblue; b++) {
if (GetHexadecimal(NULL, &i) == -1) return NULL;
if (i < 0 || MAXCOLS < i) return NULL;
avsinfo.rgbmap[r][g][b] = i;
}
for (g = 0; g < avsinfo.numgrey; g++) {
if (GetHexadecimal(NULL, &i) == -1) return NULL;
if (i < 0 || MAXCOLS < i) return NULL;
avsinfo.greymap[g] = i;
}
#ifdef DEBUG
GetAvsColormap(display, &avsinfo);
#endif /*DEBUG*/
new = (AvsInfo *) malloc( sizeof(avsinfo) );
if (new == NULL) return NULL;
(void) memcpy((char *)new,(char *)&avsinfo,sizeof(avsinfo));
return new;
}
/* gamma correct an integer over a range */
static int
GammaCorrect(int i, int num)
{
float f;
if (i <= 0) return 0;
if (i >= num-1) return 255;
f = (float) i / (float) (num-1);
return (int) (pow(f, 1/Gamma) * 255);
}
/* allocate a single color from colormap */
static long
AllocColor(Display* display, Colormap colormap, int r, int g, int b)
{
XColor cell;
cell.red = (r & 0xff) << 8;
cell.green = (g & 0xff) << 8;
cell.blue = (b & 0xff) << 8;
cell.flags = DoRed | DoGreen | DoBlue;
if (!XAllocColor(display, colormap, &cell))
return -1;
return cell.pixel;
}
/* try to allocate colors in AVS fashion from colormap */
static int
AllocColors(Display* display, AvsInfo* avsinfo)
{
int i;
int r,g,b;
long pixel;
unsigned long pixels[MAXCOLS];
i = 0;
for (r = 0; r < avsinfo->numred; r++)
for (g = 0; g < avsinfo->numgreen; g++)
for (b = 0; b < avsinfo->numblue; b++) {
pixel = AllocColor( display, avsinfo->colormap,
GammaCorrect(r, avsinfo->numred),
GammaCorrect(g, avsinfo->numgreen),
GammaCorrect(b, avsinfo->numblue)
);
if (pixel == -1) {
XFreeColors(display, avsinfo->colormap,
pixels, i, 0);
return 0;
}
pixels[i++] = avsinfo->rgbmap[r][g][b] = pixel;
}
for (g = 0; g < avsinfo->numgrey; g++) {
pixel = AllocColor( display, avsinfo->colormap,
GammaCorrect(g, avsinfo->numgrey),
GammaCorrect(g, avsinfo->numgrey),
GammaCorrect(g, avsinfo->numgrey)
);
if (pixel == -1) {
XFreeColors(display, avsinfo->colormap, pixels, i, 0);
return 0;
}
pixels[i++] = avsinfo->greymap[g] = pixel;
}
return 1;
}
/* allocate pseudocolor colormap by reducing color needs */
static int
AllocAvsColormap(Display* display, int screen, Visual* visual, AvsInfo* avsinfo)
{
if (DefaultDepth(display, screen) > 8 &&
visual->map_entries >= MAXCOLS) {
avsinfo->numred = MAXRGB;
avsinfo->numgreen = MAXRGB;
avsinfo->numblue = MAXRGB;
avsinfo->numgrey = MAXGREY;
} else if (NumRed != -1) {
avsinfo->numred = NumRed;
avsinfo->numgreen = NumGreen;
avsinfo->numblue = NumBlue;
avsinfo->numgrey = NumGrey;
} else {
avsinfo->numred = DEFRGB;
avsinfo->numgreen = DEFRGB;
avsinfo->numblue = DEFRGB;
avsinfo->numgrey = DEFGREY;
}
for (;;) {
if (AllocColors(display, avsinfo))
break;
avsinfo->numred--;
avsinfo->numgreen--;
avsinfo->numblue--;
avsinfo->numgrey = (avsinfo->numred-1)*(avsinfo->numred-1)+1;
if (avsinfo->numred < MINRGB)
return 0;
}
return 1;
}
/* create our own colormap rather than using AVS's colormap */
static AvsInfo *
CreateAvsInfo(Display* display, int screen, Visual* visual)
{
AvsInfo avsinfo, *new;
if (visual->class == TrueColor || visual->class == DirectColor)
return TrueAvsInfo(display, screen, visual);
avsinfo.colormap = DefaultColormap(display, screen);
if (!AllocAvsColormap(display, screen, visual, &avsinfo)) {
avsinfo.colormap = XCreateColormap(display,
DefaultRootWindow(display), visual, AllocNone);
if (!AllocAvsColormap(display, screen, visual, &avsinfo))
return NULL;
}
#ifdef DEBUG
GetAvsColormap(display, &avsinfo);
#endif /*DEBUG*/
new = (AvsInfo *) malloc( sizeof(avsinfo) );
if (new == NULL) return NULL;
(void) memcpy((char *)new,(char *)&avsinfo,sizeof(avsinfo));
return new;
}
/* initialize state data, select colormap and allocate colors */
static AvsInfo *
InitDisplayInfo(Display* display, int screen, Visual* visual, int child_of_avs)
{
char *avs_gamma, *avs_colors;
avs_gamma = RCget("Gamma");
if (getenv("AVS_GAMMA")) avs_gamma = getenv("AVS_GAMMA");
if (avs_gamma) {
Gamma = atof(avs_gamma);
if (Gamma <= 0.0) Gamma = 3, Gamma/=2; /* no fp constants */
}
avs_colors = RCget("Colors");
if (getenv("AVS_COLORS")) avs_colors = getenv("AVS_COLORS");
if (avs_colors) {
if (sscanf(avs_colors, " %d %d %d %d",
&NumRed, &NumGreen, &NumBlue, &NumGrey) != 4 ||
NumRed <= 0 || MAXRGB < NumRed ||
NumGreen <= 0 || MAXRGB < NumGreen ||
NumBlue <= 0 || MAXRGB < NumBlue ||
NumGrey <= 0 || MAXGREY < NumGrey)
NumRed = NumGreen = NumBlue = NumGrey = -1;
}
return child_of_avs ? GetAvsInfo(display, screen, visual) :
CreateAvsInfo(display, screen, visual) ;
}
/* return the next decoded byte from a hex string */
static int
getbyte(const char* string)
{
static unsigned char* ptr;
int i, byte;
if (string) {
ptr = (unsigned char *)string;
return EOF;
}
byte = 0;
for (i = 0; i < 2; ptr++)
if (isxdigit(*ptr))
byte = (byte<<4)|tohex[*ptr], i++;
else if (*ptr != '\n')
return EOF;
return byte;
}
/* return a block of characters from a hex string */
static int
bread(char* buf, int nbytes)
{
int i, byte;
for (i = 0; i < nbytes; i++) {
if ((byte = getbyte(NULL)) == EOF)
return i ? i : EOF;
*buf++ = byte;
}
return i;
}
/* change byte order for little-endian machines */
static void
ReverseRasterfileHeader(RF *rf)
{
reverse_int( &rf->ras_magic );
reverse_int( &rf->ras_width );
reverse_int( &rf->ras_height );
reverse_int( &rf->ras_depth );
reverse_int( &rf->ras_length );
reverse_int( &rf->ras_type );
reverse_int( &rf->ras_maptype );
reverse_int( &rf->ras_maplength );
}
/* return width and height info from rasterfile header in hex string */
static int
GetHeaderFromString(const char* string, int* width, int* height)
{
RF rf;
(void) getbyte(string);
if (bread((char *)&rf, sizeof(rf)) != sizeof(rf)) return 0;
if (IS_LITTLE_ENDIAN) ReverseRasterfileHeader(&rf);
if (rf.ras_magic != RAS_MAGIC) return 0;
*width = rf.ras_width;
*height = rf.ras_height;
return *width > 0 && *height > 0;
}
/* extract raster info from hex string */
static Raster *
GetRasterFromString(const char* string)
{
unsigned char *src, *dst, *end, *data;
int ch, size, bytes_per_line, depth;
int i, x, y, bit;
RF rf;
Raster raster, *new;
(void) getbyte(string);
if (bread((char *)&rf, sizeof(rf)) != sizeof(rf)) return NULL;
if (IS_LITTLE_ENDIAN) ReverseRasterfileHeader(&rf);
if (rf.ras_magic != RAS_MAGIC) return NULL;
if (rf.ras_depth != 1 && rf.ras_depth != 8) return NULL;
if (rf.ras_type != RT_BYTE_ENCODED) return NULL;
raster.width = rf.ras_width;
raster.height = rf.ras_height;
if (raster.width <= 0 || raster.height <= 0) return NULL;
depth = rf.ras_depth;
if (rf.ras_maptype == RMT_EQUAL_RGB) {
raster.ncolors = rf.ras_maplength/3;
if (raster.ncolors <= 0 || raster.ncolors > (1<<depth))
return NULL;
for (i = 0; i < raster.ncolors; i++) {
ch = getbyte(NULL);
if (ch == EOF) return NULL;
raster.map[i][RCOL] = ch;
}
for (i = 0; i < raster.ncolors; i++) {
ch = getbyte(NULL);
if (ch == EOF) return NULL;
raster.map[i][GCOL] = ch;
}
for (i = 0; i < raster.ncolors; i++) {
ch = getbyte(NULL);
if (ch == EOF) return NULL;
raster.map[i][BCOL] = ch;
}
} else if (depth == 1 && rf.ras_maptype == RMT_NONE) {
raster.ncolors = 2;
raster.map[0][RCOL] = 255; /* slot 0 - white */
raster.map[0][GCOL] = 255;
raster.map[0][BCOL] = 255;
raster.map[1][RCOL] = 0; /* slot 1 - black */
raster.map[1][GCOL] = 0;
raster.map[1][BCOL] = 0;
} else
return NULL;
bytes_per_line = ((raster.width*depth + 15)/16)*2;
size = bytes_per_line * raster.height;
raster.image = (unsigned char *)malloc( size );
if (raster.image == NULL) return NULL;
dst = raster.image;
end = raster.image+size;
while (dst < end) {
ch = getbyte(NULL);
if (ch == EOF) { free(raster.image); return NULL; }
if (ch == 0x80) {
int n = getbyte(NULL);
if (n == EOF) { free(raster.image); return NULL; }
if (n > 0) {
ch = getbyte(NULL);
if (ch == EOF)
{ free(raster.image); return NULL; }
while (dst < end && n-- > -1)
*dst++ = ch;
} else
*dst++ = ch;
} else
*dst++ = ch;
}
if (depth == 1) {
data = (unsigned char *)malloc( raster.width*raster.height );
if (data == NULL) { free(raster.image); return NULL; }
/* assume big-endian bit order */
for (y = 0; y < raster.height; y++) {
src = raster.image+y*bytes_per_line;
dst = data+y*raster.width;
bit = 7;
for (x = 0; x < raster.width; x++) {
*dst++ = (*src>>bit)&1;
if (--bit < 0) { src++; bit = 7; }
}
}
free( raster.image );
raster.image = data;
} else if (raster.width != bytes_per_line) {
data = (unsigned char *)malloc(raster.width*raster.height);
if (data == NULL) { free( raster.image ); return NULL; }
for (y = 0; y < raster.height; y++)
memcpy(data+y*raster.width,
raster.image+y*bytes_per_line, raster.width);
free( raster.image );
raster.image = data;
}
new = (Raster *)malloc( sizeof(raster) );
if (new == NULL) return NULL;
(void) memcpy( (void *)new, (void *)&raster, sizeof(raster) );
return new;
}
/* convert raster image to pseudocolor/staticcolor format */
static XImage *
pseudo_image(Display* display,
Visual* visual, int depth, Raster* raster, AvsInfo* avsinfo)
{
char *data;
int i, size, bits_per_pixel;
int r, g, b;
unsigned short map[MAXCOLORS];
XImage *image;
for (i = 0; i < raster->ncolors; i++) {
r = raster->map[i][RCOL];
g = raster->map[i][GCOL];
b = raster->map[i][BCOL];
if (r == g && g == b) {
g = (g * avsinfo->numgrey) / 256;
map[i] = avsinfo->greymap[g];
} else {
r = (r * avsinfo->numred) / 256;
g = (g * avsinfo->numgreen) / 256;
b = (b * avsinfo->numblue) / 256;
map[i] = avsinfo->rgbmap[r][g][b];
}
}
size = raster->width * raster->height;
if (depth > 8) {
unsigned short *ptr;
ptr = (unsigned short *)malloc( size * sizeof(short) );
if (ptr == NULL) return NULL;
for (i = 0; i < size; i++)
ptr[i] = map[ raster->image[i] ];
data = (char *)ptr;
bits_per_pixel = 16;
} else {
unsigned char *ptr;
ptr = (unsigned char *)malloc( size * sizeof(char) );
if (ptr == NULL) return NULL;
for (i = 0; i < size; i++)
ptr[i] = map[ raster->image[i] ];
data = (char *)ptr;
bits_per_pixel = 8;
}
image = XCreateImage(display, visual, depth, ZPixmap, 0, (char *)data,
raster->width, raster->height, bits_per_pixel,
raster->width*bits_per_pixel/8);
if (image == NULL) return NULL;
image->byte_order = (IS_BIG_ENDIAN ? MSBFirst : LSBFirst);
image->bitmap_unit = bits_per_pixel;
image->bitmap_bit_order = (IS_BIG_ENDIAN ? MSBFirst : LSBFirst);
image->bits_per_pixel = bits_per_pixel;
return image;
}
/* convert raster image to truecolor/directcolor format */
static XImage *
true_image(Display* display, Visual* visual, int depth, Raster* raster)
{
char *data;
int i, size;
int r,g,b;
int red_bits, green_bits, blue_bits;
int red_shift, green_shift, blue_shift;
int bits_per_pixel;
long pixels[MAXCOLORS];
XImage *image;
red_shift = count_zeros(visual->red_mask);
green_shift = count_zeros(visual->green_mask);
blue_shift = count_zeros(visual->blue_mask);
red_bits = count_ones(visual->red_mask);
green_bits = count_ones(visual->green_mask);
blue_bits = count_ones(visual->blue_mask);
for (i = 0; i < raster->ncolors; i++) {
r = GammaCorrect(raster->map[i][RCOL], MAXCOLORS);
g = GammaCorrect(raster->map[i][GCOL], MAXCOLORS);
b = GammaCorrect(raster->map[i][BCOL], MAXCOLORS);
r = ishift(r, red_shift+red_bits-8);
g = ishift(g, green_shift+green_bits-8);
b = ishift(b, blue_shift+blue_bits-8);
pixels[i] = (r & visual->red_mask) |
(g & visual->green_mask) |
(b & visual->blue_mask) ;
}
size = raster->width * raster->height;
if (depth > 16) {
unsigned long *ptr;
ptr = (unsigned long *)malloc( size * sizeof(long) );
if (ptr == NULL) return NULL;
for (i = 0; i < size; i++)
ptr[i] = pixels[ raster->image[i] ];
data = (char *)ptr;
bits_per_pixel = sizeof(long)*8;
} else if (depth > 8) {
unsigned short *ptr;
ptr = (unsigned short *)malloc( size * sizeof(short) );
if (ptr == NULL) return NULL;
for (i = 0; i < size; i++)
ptr[i] = pixels[ raster->image[i] ];
data = (char *)ptr;
bits_per_pixel = sizeof(short)*8;
} else {
unsigned char *ptr;
ptr = (unsigned char *)malloc( size * sizeof(char) );
if (ptr == NULL) return NULL;
for (i = 0; i < size; i++)
ptr[i] = pixels[ raster->image[i] ];
data = (char *)ptr;
bits_per_pixel = sizeof(char)*8;
}
image = XCreateImage(display, visual, depth, ZPixmap, 0, data,
raster->width, raster->height, bits_per_pixel,
raster->width*bits_per_pixel/8);
if (image == NULL) return NULL;
image->byte_order = (IS_BIG_ENDIAN ? MSBFirst : LSBFirst);
image->bitmap_unit = bits_per_pixel;
image->bitmap_bit_order = (IS_BIG_ENDIAN ? MSBFirst : LSBFirst);
image->bits_per_pixel = bits_per_pixel;
image->red_mask = visual->red_mask;
image->green_mask = visual->green_mask;
image->blue_mask = visual->blue_mask;
return image;
}
/* free Raster* struct */
static void
FreeRaster(Raster* raster)
{
free( (char *)raster->image );
free( (char *)raster );
}
int
initializeImageBuilder(Display* display)
/* USE:
* if (initializeImageBuilder(disp, child_of_avs, avs_visualid, &cmap)) {
* if (cmap)
* XtVaSetValues(toplevel, XtNcolormap, cmap);
* } else
* printf("could not initialize image converter.\n");
*/
{
int root = DefaultRootWindow(display);
int screen = DefaultScreen(display);
Visual* visual = DefaultVisual(display,screen);
Gamma = 3; /* DEFGAMMA with no float constants */
Gamma /= 2;
gc = XCreateGC(display, root, 0L, (XGCValues *)0);
saveinfo = InitDisplayInfo(display, screen, visual, 0);
if (saveinfo == NULL) return 0;
return 1;
}
int
getImageSize(const char* data, int* width, int* height)
/* USE:
* data = "0123456789ABCDEF\nFF00FF00FF00FF00\n...";
* if (getImageSize(data, &w, &h)
* printf("image size: %dx%d\n", w, h);
* else
* printf("not a sun raster.\n");
*/
{
return GetHeaderFromString(data, width, height);
}
Pixmap
createPixmapFromHexData(Display* display, Drawable drawable, const char* data)
/* USE:
* data = "0123456789ABCDEF\nFF00FF00FF00FF00\n...";
* getImageSize(data, &w, &h);
* pixmap = createPixmapFromHexData(disp, drawable, data);
*/
{
int screen = DefaultScreen(display);
Visual* visual = DefaultVisual(display,screen);
int depth = DefaultDepth(display,screen);
Raster *raster;
Pixmap pixmap;
XImage *image;
raster = GetRasterFromString(data);
if (raster == NULL) return 0;
if (visual->class == PseudoColor || visual->class == StaticColor)
image = pseudo_image(display, visual, depth, raster, saveinfo);
else if (visual->class == DirectColor || visual->class == TrueColor)
image = true_image(display, visual, depth, raster);
else
image = NULL;
if (image == NULL) {
FreeRaster(raster);
return 0;
}
pixmap = XCreatePixmap(display, drawable,
raster->width, raster->height, depth);
if (!pixmap) {
FreeRaster(raster);
XDestroyImage(image);
return 0;
}
XPutImage(display, pixmap, gc, image,
0, 0, 0, 0, raster->width, raster->height);
FreeRaster(raster);
XDestroyImage(image);
return pixmap;
}